/**
 * Copyright (c) 2010 - by Swandle
 * http://wangliping.net
 *
 * This module is multi-licensed and may be used under the terms
 * of any of the following licenses:
 *
 *  EPL, Eclipse Public License, http://www.eclipse.org/legal
 *  LGPL, GNU Lesser General Public License, http://www.gnu.org/licenses/lgpl.html
 *  AL, Apache License, http://www.apache.org/licenses
 *  BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php
 *
 * Please contact the author if you need another license.
 * This module is provided "as is", without warranties of any kind.
 */
 
package net.wangliping.android.tools.microblog;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;

import android.text.TextUtils;
import android.util.Log;

/**
 * Api for microblog sync.
 * 
 * <p>
 * This class is used to send microblog to follow5 and QQ.
 * And if you need, we will provide you the api of digu.com
 * and t.163.com for free.
 * 
 * <p>
 * Project home page: <a
 * href="http://api.wangliping.net/">http://api.wangliping.net</a><br>
 * Author: Swandle, China<br>
 * swandle@gmail.com
 * Multi-licensed: EPL / LGPL / AL / BSD.
 */
 
public class MicroBlogApi {
	private final String LOG_TAG = "MicroBlog";
	private final boolean DEBUG = false;
	private String mCookie = "";
	
	public String updateQQ(String username, String password, String content) {
		String verifyCode = getVerifyCode(username);
		debug(LOG_TAG, "verifyCode=" + verifyCode);
		
		String md5 = getMd5(getMd5_3(password) + verifyCode);
		debug(LOG_TAG, "md5=" + md5);

		mCookie = loginQQ(username, md5, verifyCode);
		
		if (TextUtils.isEmpty(mCookie)) {
			debug(LOG_TAG, "Could not login qq");
			return null;
		}
		debug(LOG_TAG, "mCookie=" + mCookie);
		
		String cookie = getCookieQQ("http://t.qq.com");
		
		if (TextUtils.isEmpty(cookie)) {
			debug(LOG_TAG, "Cookie is null when login qq microblog");
		} else {
			mCookie += cookie;
			debug(LOG_TAG, "mCookie=" + mCookie);
		}

		try {
			content = URLEncoder.encode(content, "utf-8");
		} catch (UnsupportedEncodingException e) {
		}
		
		String res = publishQQ("content=" + content + "&countType=&pic=&viewModel=0");
		debug(LOG_TAG, res);
		
		return res;
	}
	
	public String updateF5(String username, String password, String content, String key) {
		try {
			String auth = URLEncoder.encode(username, "utf-8") + ":" + password;
			auth = Base64Coder.encodeString(auth);
			auth = "Basic " + auth;
			
			if (TextUtils.isEmpty(key)) {
				key = "5C2D3853623122CA";
			}

			String url = "http://api.follow5.com/api/statuses/update.xml";
			content = URLEncoder.encode(content, "utf-8");
			content = "api_key=" + key + "&status=" + content;

			HttpURLConnection urlConn = (HttpURLConnection) (new URL(url)).openConnection();
			urlConn.setDoOutput(true);
			urlConn.setDoInput(true);
			urlConn.setUseCaches(false);
			urlConn.setAllowUserInteraction(false);
			urlConn.setInstanceFollowRedirects(false);
			urlConn.setRequestMethod("POST");
			urlConn.setRequestProperty("Authorization", auth);
			urlConn.connect();

			DataOutputStream out = new DataOutputStream(urlConn.getOutputStream());
			out.writeBytes(content);

			out.flush();
			out.close(); // flush and close
			
			InputStream in = urlConn.getInputStream();
			String res = readToString(in);
			
			urlConn.disconnect();
			
//			Log.d(LOG_TAG, "Update F5 response: \n" + res);
			
			return res;
		} catch (Exception e) {
		}

		return null;
	}
	
	// The username is your microblog username, not your qq number.
	private String getVerifyCode(String username) {
		String verifyURL = "http://ptlogin2.qq.com/check?uin=@" + username + "&appid=46000101";
		
		try {
		    
			HttpURLConnection urlConn = (HttpURLConnection) (new URL(verifyURL))
					.openConnection();
			urlConn.setDoOutput(true);
			urlConn.setDoInput(true);
			urlConn.setUseCaches(false);
			urlConn.setAllowUserInteraction(false);
			urlConn.setRequestMethod("GET");
			urlConn.connect();

			mCookie = urlConn.getHeaderField("Set-Cookie").split(";")[0];
			InputStream in = urlConn.getInputStream();
			String res = readToString(in);

			urlConn.disconnect();
			
			if (!TextUtils.isEmpty(res))
				return res.substring(18, 22).toUpperCase();

		} catch (Exception e) {
		}

		return null;	
	}
	
	private String loginQQ(String username, String password_md5, String verifyCode) {
		String loginURL = "http://ptlogin2.qq.com/login?u=@" + username
			+ "&p=" + password_md5
			+ "&verifycode=" + verifyCode
			+ "&aid=46000101&u1=http%3A%2F%2Ft.qq.com&h=1&from_ui=1&fp=loginerroralert";
		
		try {
			
			HttpURLConnection urlConn = (HttpURLConnection) (new URL(loginURL))
					.openConnection();
			urlConn.setDoOutput(true);
			urlConn.setDoInput(true);
			urlConn.setUseCaches(false);
			urlConn.setAllowUserInteraction(false);
			urlConn.setRequestProperty("Cookie", mCookie);
			urlConn.connect();
			List<String> setCookies = urlConn.getHeaderFields().get("set-cookie");
			
			String cookie = "";
			for(int i = 0; i < setCookies.size(); i++) {
				cookie += setCookies.get(i);
			}

			urlConn.disconnect();
			return cookie;

		} catch (Exception e) {
		}
		
		return null;		
	}
	
	private String getCookieQQ(String url) {
		try {
		    
			HttpURLConnection urlConn = (HttpURLConnection) (new URL(url))
					.openConnection();
			urlConn.setDoOutput(true);
			urlConn.setDoInput(true);
			urlConn.setUseCaches(false);
			urlConn.setAllowUserInteraction(false);
			urlConn.setRequestProperty("Cookie", mCookie);
			urlConn.setRequestMethod("GET");
			urlConn.connect();
			
			Log.d(LOG_TAG, "Connecting...");

			String cookie =  urlConn.getHeaderField("Set-Cookie");
			urlConn.disconnect();
			
			return cookie;

		} catch (Exception e) {
			Log.d(LOG_TAG, "Exception", e);
		}

		return null;
	}
	
	private String publishQQ(String content) {
		String referer_url = "http://t.qq.com";
		String url = "http://t.qq.com/publish.php";
		
		try {
		    
			HttpURLConnection urlConn = (HttpURLConnection) (new URL(url))
					.openConnection();
			urlConn.setDoOutput(true);
			urlConn.setDoInput(true);
			urlConn.setUseCaches(false);
			urlConn.setAllowUserInteraction(false);
			urlConn.setInstanceFollowRedirects(true);
			urlConn.setRequestProperty("Referer", referer_url);
			urlConn.setRequestProperty("Cookie", mCookie);
			urlConn.setRequestMethod("POST");
			urlConn.connect();
			
			DataOutputStream out = new DataOutputStream(urlConn.getOutputStream());
            out.writeBytes(content);      

            out.flush();
            out.close(); // flush and close

			InputStream in = urlConn.getInputStream();
			String res = readToString(in);
			
			urlConn.disconnect();
			
			return res;

		} catch (Exception e) {
		}

		return null;
	}
	
	private String getMd5(String value) {
		try {
			byte[] byte_value = value.getBytes();
			
			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] digest = md.digest(byte_value);			
			
			BigInteger bigInt = new BigInteger(1, digest);
			String hashtext = bigInt.toString(16);

			while (hashtext.length() < 32) {
				hashtext = "0" + hashtext;
			}

			return hashtext.toUpperCase();
		} catch (NoSuchAlgorithmException e) {
			return "";
		}
	}

	private String getMd5_3(String value) {
		try {
			byte[] byte_value = value.getBytes();
			
			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] digest = md.digest(md.digest(md.digest(byte_value)));			
			
			BigInteger bigInt = new BigInteger(1, digest);
			String hashtext = bigInt.toString(16);

			while (hashtext.length() < 32) {
				hashtext = "0" + hashtext;
			}

			return hashtext.toUpperCase();
		} catch (NoSuchAlgorithmException e) {
			return "";
		}
	}
	
	private String readToString(InputStream in) throws IOException {
		String content = "";
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] buf = new byte[1024];
		int len = 0;
		while ((len = in.read(buf)) > 0) {
			baos.write(buf, 0, len);
		}
		content = baos.toString();
		return content;
	}
	
	private void debug(final String tag, final String msg) {
		if (DEBUG)
			Log.d(tag, msg);
	}
}
